package cn.com.nes.common.util;

import cn.com.nes.common.exception.IllegalBusinessException;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Range;
import org.apache.commons.lang.StringUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yueb
 */
public class XzqhUtils {

    final static int[] prefixLengthArray = new int[]{0, 2, 4, 6, 9, 12};

    public static String getAreaCodeLikeStr(String xzqhdm, String xzqhJb) {
        String subXzqhDigit = subXzqhDigit(xzqhJb);
        String xzqhdmLike = xzqhdm.substring(0, Integer.parseInt(subXzqhDigit));
        return xzqhdmLike;
    }

    public static String subXzqhDigit(String xzqhJb) {

        String subXzqhDigit = "";
        xzqhJb = StrUtil.nullToDefault(xzqhJb, "");
        switch (xzqhJb) {
            case "0":
                subXzqhDigit = "0";
                break;
            case "1":
                subXzqhDigit = "2";
                break;
            case "2":
                subXzqhDigit = "4";
                break;
            case "3":
                subXzqhDigit = "6";
                break;
            case "4":
                subXzqhDigit = "9";
                break;
            case "5":
                subXzqhDigit = "12";
                break;
            case "6":
                subXzqhDigit = "15";
                break;
            default:
                subXzqhDigit = "2";
        }
        return subXzqhDigit;
    }

    public static int getHightLevel(String xzqhdms) {
        String[] split = xzqhdms.split(";");
        final List<String> regionCodes = Arrays.stream(split).filter(StrUtil::isNotBlank).collect(Collectors.toList());
        if (regionCodes.size() == 1) {
            return getRegionLevel(regionCodes.get(0));
        }
        for (int level = 1; level < 5; level++) {
            Set<String> prefixes = new HashSet<>(2);
            for (String regionCode : regionCodes) {
                prefixes.add(getRegionCodePrefix(regionCode, level));
                if (prefixes.size() > 1) {
                    return level - 1;
                }
            }
        }
        return 4;
    }

    public static String getDownXzqh(String xzqhdm, String xzqhjb, String field) {
        int jb = Integer.parseInt(xzqhjb);
        StringBuffer sb = new StringBuffer();
        switch (jb) {
            case 0:
                if (field != null) {
                    sb.append(" concat(substr(").append(field).append(",1,2),'') ");
                } else {
                    sb.append(" concat(substr(").append(xzqhdm).append(",1,2),'') ");
                }
                break;
            case 1:
                //sb.append(" concat(substr(").append(xzqhdm_fld).append(",1,4),'00000000') ") ;
                if (field != null) {
                    sb.append(" if(concat(substr(")
                            .append(field)
                            .append(", 1, 4),'00000000')='110100000000',concat(substr(")
                            .append(field)
                            .append(", 1, 6),'000000'),concat(substr(")
                            .append(field)
                            .append(", 1, 4),'00000000')) ");
                } else {
                    sb.append(" if(concat(substr(")
                            .append(xzqhdm)
                            .append(", 1, 4),'00000000')='110100000000',concat(substr(")
                            .append(xzqhdm)
                            .append(", 1, 6),'000000'),concat(substr(")
                            .append(xzqhdm)
                            .append(", 1, 4),'00000000')) ");
                }
                break;
            case 2:
                if (field != null) {
                    sb.append(" concat(substr(").append(field).append(",1,6),'000000') ");
                } else {
                    sb.append(" concat(substr(").append(xzqhdm).append(",1,6),'000000') ");
                }
                break;
            case 3:
                if (field != null) {
                    sb.append(" concat(substr(").append(field).append(",1,9),'000') ");
                } else {
                    sb.append(" concat(substr(").append(xzqhdm).append(",1,9),'000') ");
                }
                break;
            case 4:
                if (field != null) {
                    sb.append(" concat(substr(").append(field).append(",1,12)) ");
                } else {
                    sb.append(" concat(substr(").append(xzqhdm).append(",1,12)) ");
                }
                break;
            default:
                if (field != null) {
                    sb.append(" ").append(field).append(" ");
                } else {
                    sb.append(" ").append(xzqhdm).append(" ");
                }
                break;
        }
        return sb.toString();
    }

    public static List<String> splitRegionCodes(String regionCodes) {
        return Arrays.stream(Optional.ofNullable(regionCodes).orElse("").split(";"))
                .filter(StrUtil::isNotBlank)
                .map(code -> getRegionCodePrefix(code) + "%")
                .collect(Collectors.toList());
    }

    /**
     * 查询行政区划代码前缀
     * 根据行政区划级别，截取行政区划代码
     * 例： 86 -> "“； 110105000000 -> 110105
     * @param regionCode 要查询的行政区划代码
     * @return
     */
    public static String getRegionCodePrefix(String regionCode) {
        int level = XzqhUtils.getRegionLevel(regionCode);
        return getRegionCodePrefix(regionCode, level);
    }

    public static String getRegionCodePrefix(String regionCode, int level) {
        return Optional.ofNullable(regionCode).filter(StrUtil::isNotBlank).map(code -> {
            code = StrUtil.padAfter(code, 12, '0');
            int prefixLength = XzqhUtils.getRegionCodePrefixLength(level);
            code = code.substring(0, prefixLength);
            return code;
        }).orElse(regionCode);
    }

    public static int getRegionLevel(String regionCode) {
        if (StrUtil.isBlank(regionCode) || regionCode.startsWith("86") || regionCode.length() > 12) {
            return 0;
        }
        regionCode = StrUtil.padAfter(regionCode, 12, '0');
        if (regionCode.substring(2).equals("0000000000")) {
            return 1;
        } else if (regionCode.substring(4).equals("00000000")) {
            return 2;
        } else if (regionCode.substring(6).equals("000000")) {
            return 3;
        } else if (regionCode.substring(9).equals("000")) {
            return 4;
        } else if (regionCode.length() == 15) {
            return 6;
        }
        return 5;
    }

    public static String getParentRegionCode(String regionCode, int level) {
        return Range.openClosed(0, 6)
                .contains(level) ? level == 1 ? getRegionCodePrefix(regionCode, level) : StrUtil.padAfter(getRegionCodePrefix(regionCode, level), 12, '0') : regionCode;
    }

    public static String getParentRegionCode(String regionCode) {
        int level = getRegionLevel(regionCode);
        if (level == 1) {
            return "86";
        }
        if (level == 2) {
            return getRegionCodePrefix(regionCode, level-1);
        }
        return Range.openClosed(1, 6)
                .contains(level) ? StrUtil.padAfter(getRegionCodePrefix(regionCode, level - 1), 12, '0') : regionCode;
    }

    public static void main(String[] args) {
        String code = getParentRegionCode("110107001003", 1);
        System.out.println("code: [" + code + "]"); // 110105

        System.out.println(getParentRegionCode("11"));
    }

    public static int getRegionCodePrefixLength(int level) {
        return prefixLengthArray[level < 0 || level > prefixLengthArray.length ? 0 : level];
    }


    public static String getSjXzqhdm(String xzqhdm) {
        int level = XzqhUtils.getRegionLevel(xzqhdm);
        return StrUtil.padAfter(XzqhUtils.getRegionCodePrefix(xzqhdm, level - 1), 12, '0');
    }

    public static String zero(int i) {
        String a = "";
        for (int i1 = 0; i1 < i; i1++) {
            a += "0";
        }
        return a;
    }

    /**
     * 去除xzqhdm中的0
     * @return
     */
    public static String delZeroInXzqhdm(String xzqhdm) {
        char[] xzqhdmList = xzqhdm.toCharArray();
        int flag = xzqhdmList.length - 1;
        while (flag >= 0) {
            if (xzqhdmList[flag] != '0') {
                break;
            }
            flag -= 1;
        }
        String newXzqhdm = "";
        for (int i = 0; i <= flag; i++) {
            newXzqhdm = newXzqhdm + xzqhdmList[i];
        }
        return newXzqhdm;
    }

    public static String comparePermission(String xzqh1, String xzqh2, String level1, String level2) {
        String a = xzqh1.substring(0, Integer.parseInt(subXzqhDigit(level1)));
        //全国行政区划代码
        String CN = "86";
        if (CN.equals(xzqh2) || StrUtil.isBlank(xzqh2)) {
            //传入条件为空或者为全国,返回的查询条件为当前用户的最大权限
            return a;
        } else if (CN.equals(xzqh1)) {
            //当前用户权限为86,返回查询条件为传入查询范围
            return xzqh2.substring(0, Integer.parseInt(subXzqhDigit(level2)));
        } else {
            String b = xzqh2.substring(0, Integer.parseInt(subXzqhDigit(level2)));
            if (a.equals(xzqh2.substring(0, Integer.parseInt(subXzqhDigit(level1))))) {
                //传入查询范围小于等于当前用的权限范围,返回查询条件为传入查询条件
                return b;
            } else {
                //无传入行政区划权限
                return "0";
            }
        }
    }

    /**
     * 根据行政区划代码集合返回指定行政区划代码子集或指定等级子集
     * @param areaCodeSet 基础行政区划代码集合
     * @param areaCode    指定行政区划代码
     * @return
     */
    public static Set<String> getChildLevelAreaCodeSet(Set<String> areaCodeSet, String areaCode) {
        if (CollectionUtil.isEmpty(areaCodeSet)) {
            throw new IllegalBusinessException("areaCodeSet must not be empty");
        }

        // 按areaCode筛选数据
        Integer topAreaLevel = null;
        if (StrUtil.isNotBlank(areaCode)) {
            areaCodeSet = areaCodeSet.stream()
                    .filter(n -> n.startsWith(XzqhUtils.getRegionCodePrefix(areaCode)) && !n.equals(areaCode))
                    .collect(Collectors.toSet());
            topAreaLevel = XzqhUtils.getHightLevel(areaCode) + 1;
        }

        // 按等级收集行政区划代码
        Map<Integer, Set<String>> areaCodeLevelMap = new HashMap<>();
        for (String areaCode_1 : areaCodeSet) {
            int regionLevel = XzqhUtils.getRegionLevel(areaCode_1);

            if (ObjectUtil.isNull(areaCodeLevelMap.get(regionLevel))) {
                areaCodeLevelMap.put(regionLevel, new HashSet<>(Collections.singletonList(areaCode_1)));
                continue;
            }
            areaCodeLevelMap.get(regionLevel).add(areaCode_1);
        }

        // 获取集合中最末级等级
        Optional<Integer> lowestLevel = areaCodeLevelMap.keySet().stream().max(Integer::compareTo);
        if (!lowestLevel.isPresent()) {
            return new HashSet<>(Collections.emptyList());
        }
        // 获取集合中最高级等级
        Optional<Integer> topLevel = areaCodeLevelMap.keySet().stream().min(Integer::compareTo);

        // 补全所有上级行政区划代码
        for (int childLevel = lowestLevel.get(); childLevel >= 1; childLevel--) {
            Set<String> childAreaCodeSet = areaCodeLevelMap.get(childLevel);

            if ((ObjectUtil.isNotNull(topAreaLevel) && childLevel == topAreaLevel) || (ObjectUtil.isNull(topAreaLevel) && childAreaCodeSet.size() == 1 && childLevel <= topLevel.get()) || 1 == childLevel) {
                topAreaLevel = childLevel;
                break;
            }

            for (String childAreaCode : childAreaCodeSet) {
                Set<String> parentAreaCodeSet = areaCodeLevelMap.get(childLevel - 1);
                if (CollectionUtil.isEmpty(parentAreaCodeSet)) {
                    parentAreaCodeSet = new HashSet<>();
                    areaCodeLevelMap.put(childLevel - 1, parentAreaCodeSet);
                }
                parentAreaCodeSet.add(XzqhUtils.getParentRegionCode(childAreaCode));
            }
        }

        // 处理省级行政区划代码 - 去掉后缀的0
        if (CollectionUtil.isNotEmpty(areaCodeLevelMap.get(1))) {
            areaCodeLevelMap.put(1, areaCodeLevelMap.get(1)
                    .stream()
                    .map(XzqhUtils::getRegionCodePrefix)
                    .collect(Collectors.toSet()));
        }

        return areaCodeLevelMap.get(topAreaLevel);
    }

    /**
     * 将xzqhdm集合转为xzqhdm数组
     * @param xzqhdms
     * @return
     */
    public static String[] getXzqhdms(String xzqhdms) {
        List<String> list = new ArrayList<>();
        if (StringUtils.isEmpty(xzqhdms)) {
            xzqhdms = "";
        }
        String[] split = xzqhdms.split(";");
        List<String> collect = Arrays.stream(split).collect(Collectors.toList());
        List<Map> xzqhdmsAndxzqhjbsList = collect.stream().map(xzqhdm -> {
            Map<String, String> map = new HashMap<>();
            map.put("xzqhdm", xzqhdm);
            map.put("xzqhjb", XzqhUtils.getRegionLevel(xzqhdm) + "");
            return map;
        }).collect(Collectors.toList());
        for (Map<String, String> map : xzqhdmsAndxzqhjbsList) {
            if (!StringUtils.isEmpty(map.get("xzqhdm"))) {
                String subXzqhDigit = XzqhUtils.subXzqhDigit(map.get("xzqhjb"));
                if (subXzqhDigit.equals("12")) {
                    String xzqhQuery = map.get("xzqhdm").substring(0, Integer.parseInt(subXzqhDigit));
                    list.add(xzqhQuery);
                    continue;
                }
                String xzqhQuery = map.get("xzqhdm").substring(0, Integer.parseInt(subXzqhDigit));
                list.add(xzqhQuery + "%");
            }
        }
        String[] strings = list.toArray(new String[list.size()]);
        return list.size() != 0 ? strings : null;
    }

}
